fix: Copy mutable collections before passing to scope observers#7807
fix: Copy mutable collections before passing to scope observers#7807
Conversation
SentryScope passes mutable collections to scope observers inside @synchronized blocks. Observers like WatchdogTermination dispatch async work that iterates the collection after the lock is released, racing with concurrent mutations — causing EXC_BAD_ACCESS. Copy collections before passing to observers, consistent with the existing public getter methods that already return copies.
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. Bug Fixes 🐛
Internal Changes 🔧Deps
🤖 This preview updates automatically when you update the PR. |
|
@cursor review |
|
@sentry review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit dd9ad6b. Configure here.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7807 +/- ##
=============================================
- Coverage 85.418% 85.408% -0.011%
=============================================
Files 487 487
Lines 29195 29195
Branches 12632 12634 +2
=============================================
- Hits 24938 24935 -3
- Misses 4207 4209 +2
- Partials 50 51 +1
... and 4 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
philprime
left a comment
There was a problem hiding this comment.
Approving this already, but please take a look at my comments and decide what makes more sense.
📲 Install BuildsiOS
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 3461f50 | 1228.08 ms | 1263.37 ms | 35.29 ms |
| 5b1e2a1 | 1217.63 ms | 1245.49 ms | 27.86 ms |
| e1e5f3b | 1220.60 ms | 1241.63 ms | 21.04 ms |
| fe6228d | 1215.81 ms | 1234.04 ms | 18.23 ms |
| 93ef486 | 1220.22 ms | 1244.96 ms | 24.74 ms |
| e06cf5f | 1222.96 ms | 1254.66 ms | 31.70 ms |
| 14bb180 | 1222.75 ms | 1252.47 ms | 29.72 ms |
| 387fbe4 | 1226.19 ms | 1251.98 ms | 25.79 ms |
| b2f3bdd | 1219.09 ms | 1256.42 ms | 37.33 ms |
| a1a9260 | 1192.15 ms | 1229.80 ms | 37.64 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 3461f50 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| 5b1e2a1 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| e1e5f3b | 24.14 KiB | 1.06 MiB | 1.04 MiB |
| fe6228d | 24.14 KiB | 1.11 MiB | 1.08 MiB |
| 93ef486 | 24.14 KiB | 1.06 MiB | 1.04 MiB |
| e06cf5f | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| 14bb180 | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| 387fbe4 | 24.14 KiB | 1.07 MiB | 1.04 MiB |
| b2f3bdd | 24.14 KiB | 1.11 MiB | 1.08 MiB |
| a1a9260 | 24.14 KiB | 1.08 MiB | 1.06 MiB |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 59d8fd0. Configure here.

📜 Description
Copy mutable collections (
_contextDictionary,_tagDictionary,_extraDictionary,_fingerprintArray,_attributesDictionary) before passing them to scope observers inSentryScope.m. This prevents a race condition where observers dispatch async work that iterates the collection after the@synchronizedlock is released, while another thread mutates it concurrently.Also updates the misleading thread-safety comment in
SentryWatchdogTerminationScopeObserver.swiftto accurately describe the guarantee.💡 Motivation and Context
Fixes a launch crash (
EXC_BAD_ACCESSinobjc_msgSend) reported in getsentry/sentry-react-native#5995 affecting <1% of cold launches on iOS 26+. The crash occurs becauseSentryWatchdogTerminationScopeObservercaptures mutable collection references and dispatches async disk writes, racing with concurrent scope mutations.The public getter methods (
context,extras,tags,fingerprints,attributes) already return.copy— this fix makes observer notifications consistent with that pattern.💚 How did you test it?
testModifyingFromMultipleThreads_withObserverAsyncDispatch— a concurrent stress test that rapidly mutates scope context/tags/extras/fingerprint from multiple threads while an observer with async dispatch is activeSentryScopeSwiftTests(59 tests) passSentryWatchdogTerminationScopeObserverTests(18 tests) passmake format,make analyze,make build-iosall clean📝 Checklist
You have to check all boxes before merging:
sendDefaultPIIis enabled.